package xyz.icxl.android.architecture.ui.mvvm

import androidx.annotation.StringRes
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import coil.request.NullRequestDataException
import com.blankj.utilcode.util.SnackbarUtils
import com.blankj.utilcode.util.StringUtils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import xyz.icxl.android.architecture.data.*
import java.util.*

open class BaseViewModel : ViewModel() {

    companion object {
        const val HTTP_REP_NULL_MESSAGE = "data empty"
        const val DEFAULT_PAGE_SIZE = 30
    }

    protected val _loadingStatus = MutableLiveData<PageLoadingStatus>()
    val loadingStatus: LiveData<PageLoadingStatus>
        get() = _loadingStatus

    protected val _snackbarStatus = MutableLiveData<PageSnackBarStatus>()
    val snackbarStatus: LiveData<PageSnackBarStatus>
        get() = _snackbarStatus

    fun postSnackbarStatus(status: PageSnackBarStatus) {
        _snackbarStatus.postValue(status)
    }

    fun postSnackbarStatus(
        show: Boolean = false,
        showError: Boolean = false,
        showSuccess: Boolean = false,
        showWarning: Boolean = false,
        isShowTop: Boolean = true,
        message: CharSequence,
        dismiss: Boolean = false,
        @SnackbarUtils.Duration duration: Int = SnackbarUtils.LENGTH_SHORT,
    ) {
        postSnackbarStatus(
            PageSnackBarStatus(
                show,
                showError,
                showSuccess,
                showWarning,
                isShowTop,
                message,
                dismiss,
                duration
            )
        )
    }

    fun postLoadingShow(msg: CharSequence = "···",isCancelable: Boolean = true) {
        _loadingStatus.postValue(PageLoadingStatus(true, text = msg, isCancelable = isCancelable))
    }

    fun postLoadingFail(msg: String) {
        _loadingStatus.postValue(PageLoadingStatus(fail = true, text = msg))
    }

    fun postLoadingSuccess(msg: String = if(Locale.getDefault().language=="zh") "成功" else "Successful") {
        _loadingStatus.postValue(PageLoadingStatus(success = true, text = msg))
    }

    fun postLoadingDismiss() {
        _loadingStatus.postValue(PageLoadingStatus(dismiss = true))
    }

    /**
     * 页面Loading状态
     */
    data class PageLoadingStatus(
        /**
         * 现实loading 布局
         */
        val show: Boolean = false,
        /**
         * 显示加载成功的布局
         */
        val success: Boolean = false,
        /**
         * 显示加载失败的布局
         */
        val fail: Boolean = false,
        /**
         * 各个状态对应的文字
         */
        val text: CharSequence? = null,
        val dismiss: Boolean = false,
        /**
         * 标记
         */
        val flag: Int = 0,
        /**
         * 是否可点击取消弹窗
         */
        val isCancelable:Boolean = true
    )


    data class PageSnackBarStatus(
        val show: Boolean = false,
        val showError: Boolean = false,
        val showSuccess: Boolean = false,
        val showWarning: Boolean = false,
        val isShowTop: Boolean = true,
        val message: CharSequence,
        val dismiss: Boolean = false,
        /**
         * 显示时长
         * - [SnackbarUtils.LENGTH_INDEFINITE]
         * - [SnackbarUtils.LENGTH_SHORT]
         * - [SnackbarUtils.LENGTH_LONG]
         */
        @SnackbarUtils.Duration val duration: Int = SnackbarUtils.LENGTH_SHORT,
    )

    data class DownloadStatus(
        val downloadIng: Boolean = false,
        val downloadProgress: Int = -1,
        val downloadFail: String = "",
        val downloadSuccess: String = ""
    )

    data class APIRequestStatus<T>(
        val requestIng: Boolean = false,
        val requestSuccess: T? = null,
        val requestFail: String = "",
        val flag: Boolean = false,
        val position: Int = -1,
        val isNoMoreData: Boolean = false,
    ) {
        val isFail:Boolean
            get() = requestFail.isNotEmpty()
        companion object {
            fun <T> requestIng(flag: Boolean = false): APIRequestStatus<T> {
                return APIRequestStatus<T>(requestIng = true, flag = flag)
            }

            fun <T> requestFail(
                msg: String,
                flag: Boolean = false,
                position: Int = -1
            ): APIRequestStatus<T> =
                APIRequestStatus(requestFail = msg, flag = flag, position = position)

            fun <T> requestSuccess(data: T, flag: Boolean = false, position: Int = -1) =
                APIRequestStatus(requestSuccess = data, flag = flag, position = position)

            fun <T> requestSuccess(data: T, flag: Boolean = false, isNoMoreData: Boolean) =
                APIRequestStatus(
                    requestSuccess = data,
                    flag = flag,
                    isNoMoreData = isNoMoreData
                )
        }
    }

    fun <T> createAPIRequestStatusMutableLiveData() = MutableLiveData<APIRequestStatus<T>>()

    /**
     * 接口请求异常
     */
    open fun onHttpFail(data: BRep<*>) {

    }

    val mException: MutableLiveData<Throwable> = MutableLiveData()


    fun launchOnUI(block: suspend CoroutineScope.() -> Unit) {
        viewModelScope.launch { block() }

    }

    suspend fun <T> launchOnIO(block: suspend CoroutineScope.() -> T): T {
        return withContext(Dispatchers.IO, block)
    }


    protected val Int.resStr: CharSequence
        get() = StringUtils.getString(this)

    protected fun Int.resStr(vararg formatArgs: Any): CharSequence =
        StringUtils.getString(this, formatArgs)

    fun <T : Any> ApiResult<T>.process(status: MutableLiveData<APIRequestStatus<T?>>) {
        success {
            status.value = APIRequestStatus.requestSuccess(it)
        }
        error { _, msg ->
            status.value = APIRequestStatus.requestFail(msg)
        }
    }

    fun <T : Any> ApiResult<MutableList<T>>.processList(status: MutableLiveData<APIRequestStatus<MutableList<T>>>,flag: Boolean = false): ApiResult<MutableList<T>> {
        success {
            status.value = APIRequestStatus.requestSuccess(it?: arrayListOf(),flag)
        }
        error { _, msg ->
            status.value = APIRequestStatus.requestFail(msg,flag)
        }
        return this
    }

    protected fun <T : Any> ApiResult<T>.processLimitNull(status: MutableLiveData<APIRequestStatus<T>>,flag: Boolean = false) {
        success {
            if (it == null) {
                status.value = APIRequestStatus.requestFail("数据为NULL")
            } else {
                status.value = APIRequestStatus.requestSuccess(it,flag)
            }

        }
        error { _, msg ->
            status.value = APIRequestStatus.requestFail(msg, flag = flag)
        }
    }


    fun <T : Any> ApiResult<MutableList<T>>.processList(
        refresh: Boolean,
        status: MutableLiveData<APIRequestStatus<MutableList<T>>>,
        success: () -> Unit
    ) {
        checkResult(success = {
            status.value = APIRequestStatus.requestSuccess(
                data = it ?: arrayListOf(),
                flag = refresh,
                isNoMoreData = (it?.size ?: 0) < DEFAULT_PAGE_SIZE
            )
            success()
        }, error = {
            status.value = APIRequestStatus.requestFail(it)
        })
    }

    fun getResStr(@StringRes resId: Int): String = StringUtils.getString(resId)

}